﻿using System;
using System.Collections.Generic;
using System.Linq;

namespace EstateNuke.Data
{
    public partial class EstateNukeCore
    {
        #region Company Level

        #region Department

        /// <summary>
        /// </summary>
        /// <returns></returns>
        public IList<Department> GetAllDepartments()
        {
            return GetAllDepartments(CompanyEnum.Default);
        }

        /// <summary>
        /// </summary>
        /// <param name = "company"></param>
        /// <returns></returns>
        public IList<Department> GetAllDepartments(Company company)
        {
            return GetAllDepartments(CompanyEnum.Default, true);
        }

        /// <summary>
        /// </summary>
        /// <param name = "company"></param>
        /// <param name = "withoutDeleted"></param>
        /// <returns></returns>
        public IList<Department> GetAllDepartments(Company company, bool withoutDeleted)
        {
            if (company == null)
            {
                throw new ArgumentNullException("company");
            }
            var departments = Departments.Where(department => department.CompanyId == company.Id);
            if (withoutDeleted)
            {
                departments = departments.Where(department => department.IsDeleted == false);
            }
            departments = departments.OrderBy(department => department.Id);
            return departments.ToList();
        }

        /// <summary>
        /// </summary>
        /// <param name = "id"></param>
        /// <returns></returns>
        public Department GetDepartmentById(int id)
        {
            return GetDepartmentById(id, true, true);
        }

        /// <summary>
        /// </summary>
        /// <param name = "id"></param>
        /// <param name = "deepLoad"></param>
        /// <param name = "withoutDeleted"></param>
        /// <returns></returns>
        public Department GetDepartmentById(int id, bool deepLoad, bool withoutDeleted)
        {
            var departments = (deepLoad ? Departments.Include("InternalEmployees") : Departments).Where(department => department.Id == id);
            if (withoutDeleted)
            {
                departments = departments.Where(department => department.IsDeleted == false);
            }
            return departments.FirstOrDefault();
        }

        /// <summary>
        /// </summary>
        /// <param name = "name"></param>
        /// <returns></returns>
        public Department GetDepartmentByName(string name)
        {
            return GetDepartmentByName(name, true, true);
        }

        /// <summary>
        /// </summary>
        /// <param name = "name"></param>
        /// <param name = "deepLoad"></param>
        /// <param name = "withoutDeleted"></param>
        /// <returns></returns>
        public Department GetDepartmentByName(string name, bool deepLoad, bool withoutDeleted)
        {
            var departments = (deepLoad ? Departments.Include("InternalEmployees") : Departments).Where(department => department.Name == name);
            if (withoutDeleted)
            {
                departments = departments.Where(department => department.IsDeleted == false);
            }
            return departments.FirstOrDefault();
        }

        #endregion

        #region District

        /// <summary>
        /// </summary>
        /// <returns></returns>
        public IList<District> GetAllDistricts()
        {
            return GetAllDistricts(CompanyEnum.Default);
        }

        /// <summary>
        /// </summary>
        /// <param name = "company"></param>
        /// <returns></returns>
        public IList<District> GetAllDistricts(Company company)
        {
            return GetAllDistricts(CompanyEnum.Default, true);
        }

        /// <summary>
        /// </summary>
        /// <param name = "company"></param>
        /// <param name = "withoutDeleted"></param>
        /// <returns></returns>
        public IList<District> GetAllDistricts(Company company, bool withoutDeleted)
        {
            if (company == null)
            {
                throw new ArgumentNullException("company");
            }
            var districts = Districts.Where(district => district.CompanyId == company.Id);
            if (withoutDeleted)
            {
                districts = districts.Where(district => district.IsDeleted == false);
            }
            districts = districts.OrderBy(district => district.Region).OrderBy(district => district.Name);
            return districts.ToList();
        }

        /// <summary>
        /// </summary>
        /// <param name = "id"></param>
        /// <returns></returns>
        public District GetDistrictById(int id)
        {
            return GetDistrictById(id, true, true);
        }

        /// <summary>
        /// </summary>
        /// <param name = "id"></param>
        /// <param name = "deepLoad"></param>
        /// <param name = "withoutDeleted"></param>
        /// <returns></returns>
        public District GetDistrictById(int id, bool deepLoad, bool withoutDeleted)
        {
            var districts = (deepLoad ? Districts.Include("InternalCustomers") : Districts).Where(district => district.Id == id);
            if (withoutDeleted)
            {
                districts = districts.Where(district => district.IsDeleted == false);
            }
            return districts.FirstOrDefault();
        }

        /// <summary>
        /// </summary>
        /// <param name = "name"></param>
        /// <returns></returns>
        public District GetDistrictByName(string name)
        {
            return GetDistrictByName(name, true, true);
        }

        /// <summary>
        /// </summary>
        /// <param name = "name"></param>
        /// <param name = "deepLoad"></param>
        /// <param name = "withoutDeleted"></param>
        /// <returns></returns>
        public District GetDistrictByName(string name, bool deepLoad, bool withoutDeleted)
        {
            var districts = (deepLoad ? Districts.Include("InternalCustomers") : Districts).Where(district => district.Name == name);
            if (withoutDeleted)
            {
                districts = districts.Where(district => district.IsDeleted == false);
            }
            return districts.FirstOrDefault();
        }

        #endregion

        #region Project

        /// <summary>
        /// </summary>
        /// <returns></returns>
        public IList<Project> GetAllProjects()
        {
            return GetAllProjects(CompanyEnum.Default);
        }

        /// <summary>
        /// </summary>
        /// <param name = "company"></param>
        /// <returns></returns>
        public IList<Project> GetAllProjects(Company company)
        {
            return GetAllProjects(CompanyEnum.Default, true);
        }

        /// <summary>
        /// </summary>
        /// <param name = "company"></param>
        /// <param name = "withoutDeleted"></param>
        /// <returns></returns>
        public IList<Project> GetAllProjects(Company company, bool withoutDeleted)
        {
            if (company == null)
            {
                throw new ArgumentNullException("company");
            }
            var projects = Projects.Where(project => project.CompanyId == company.Id);
            if (withoutDeleted)
            {
                projects = projects.Where(project => project.IsDeleted == false);
            }
            projects = projects.OrderBy(project => project.Id);
            return projects.ToList();
        }

        /// <summary>
        /// </summary>
        /// <param name = "id"></param>
        /// <returns></returns>
        public Project GetProjectById(int id)
        {
            return GetProjectById(id, true, true);
        }

        /// <summary>
        /// </summary>
        /// <param name = "id"></param>
        /// <param name = "deepLoad"></param>
        /// <param name = "withoutDeleted"></param>
        /// <returns></returns>
        public Project GetProjectById(int id, bool deepLoad, bool withoutDeleted)
        {
            var projects = (deepLoad ? Projects.Include("InternalBuildings").Include("InternalCustomers").Include("InternalEmployees").Include("InternalProjectUsers") : Projects).Where(project => project.Id == id);
            if (withoutDeleted)
            {
                projects = projects.Where(project => project.IsDeleted == false);
            }
            return projects.FirstOrDefault();
        }

        /// <summary>
        /// </summary>
        /// <param name = "name"></param>
        /// <returns></returns>
        public Project GetProjectByName(string name)
        {
            return GetProjectByName(name, true, true);
        }

        /// <summary>
        /// </summary>
        /// <param name = "name"></param>
        /// <param name = "deepLoad"></param>
        /// <param name = "withoutDeleted"></param>
        /// <returns></returns>
        public Project GetProjectByName(string name, bool deepLoad, bool withoutDeleted)
        {
            var projects = (deepLoad ? Projects.Include("InternalBuildings").Include("InternalCustomers").Include("InternalEmployees").Include("InternalProjectUsers") : Projects).Where(project => project.Name == name);
            if (withoutDeleted)
            {
                projects = projects.Where(project => project.IsDeleted == false);
            }
            return projects.FirstOrDefault();
        }

        #endregion

        #region User

        /// <summary>
        /// </summary>
        /// <returns></returns>
        public IList<User> GetAllUsers()
        {
            return GetAllUsers(CompanyEnum.Default);
        }

        /// <summary>
        /// </summary>
        /// <param name = "company"></param>
        /// <returns></returns>
        public IList<User> GetAllUsers(Company company)
        {
            return GetAllUsers(CompanyEnum.Default, true);
        }

        /// <summary>
        /// </summary>
        /// <param name = "company"></param>
        /// <param name = "withoutDeleted"></param>
        /// <returns></returns>
        public IList<User> GetAllUsers(Company company, bool withoutDeleted)
        {
            if (company == null)
            {
                throw new ArgumentNullException("company");
            }
            var users = Users.Where(user => user.CompanyId == company.Id);
            if (withoutDeleted)
            {
                users = users.Where(user => user.IsDeleted == false);
            }
            users = users.OrderBy(user => user.Id);
            return users.ToList();
        }

        /// <summary>
        /// </summary>
        /// <param name = "id"></param>
        /// <returns></returns>
        public User GetUserById(int id)
        {
            return GetUserById(id, true, true);
        }

        /// <summary>
        /// </summary>
        /// <param name = "id"></param>
        /// <param name = "deepLoad"></param>
        /// <param name = "withoutDeleted"></param>
        /// <returns></returns>
        public User GetUserById(int id, bool deepLoad, bool withoutDeleted)
        {
            var users = (deepLoad ? Users.Include("InternalProjectUsers") : Users).Where(user => user.Id == id);
            if (withoutDeleted)
            {
                users = users.Where(user => user.IsDeleted == false);
            }
            return users.FirstOrDefault();
        }

        /// <summary>
        /// </summary>
        /// <param name = "name"></param>
        /// <returns></returns>
        public User GetUserByName(string name)
        {
            return GetUserByName(name, true, true);
        }

        /// <summary>
        /// </summary>
        /// <param name = "name"></param>
        /// <param name = "deepLoad"></param>
        /// <param name = "withoutDeleted"></param>
        /// <returns></returns>
        public User GetUserByName(string name, bool deepLoad, bool withoutDeleted)
        {
            var users = (deepLoad ? Users.Include("InternalProjectUsers") : Users).Where(user => user.UserName == name);
            if (withoutDeleted)
            {
                users = users.Where(user => user.IsDeleted == false);
            }
            return users.FirstOrDefault();
        }

        #endregion

        #endregion

        #region Employee Plan

        /// <summary>
        /// </summary>
        /// <param name = "employees"></param>
        /// <param name = "beginDate"></param>
        /// <param name = "endDate"></param>
        /// <returns></returns>
        public IDictionary<Employee, Tuple<decimal, int>> GetEmployeesSaleArea(IList<Employee> employees, DateTime beginDate, DateTime endDate)
        {
            var employeeIds = employees.Select(employee => employee.Id).Distinct().ToList();
            var employeeSaleAreas = Employees.Where(employee => employee.IsDeleted == false && employeeIds.Contains(employee.Id)).Select(employee => new
                                                                                                                                                         {
                                                                                                                                                             Employee = employee,
                                                                                                                                                             Rooms = employee.InternalAgreements.Where(agreement => agreement.IsDeleted == false && agreement.InternalContracts.Any(contract => contract.IsDeleted == false && contract.SignatureDate >= beginDate && contract.SignatureDate < endDate) && agreement.Room.IsDeleted == false && agreement.Room.ActiveAgreementId == agreement.Id && (agreement.Room.RoomStateId == 5 || agreement.Room.RoomStateId == 6)).Select(agreement => agreement.Room),
                                                                                                                                                         }).ToList();
            return employeeSaleAreas.ToDictionary(employeeSaleArea => employeeSaleArea.Employee, employeeSaleArea => Tuple.Create(employeeSaleArea.Rooms.Sum(room => room.SaleArea), employeeSaleArea.Rooms.Count()));
        }

        /// <summary>
        /// </summary>
        /// <param name = "employees"></param>
        /// <param name = "beginDate"></param>
        /// <param name = "endDate"></param>
        /// <returns></returns>
        public IDictionary<Employee, Tuple<decimal, int>> GetEmployeesLeaseArea(IList<Employee> employees, DateTime beginDate, DateTime endDate)
        {
            var employeeIds = employees.Select(employee => employee.Id).Distinct().ToList();
            var employeeLeaseAreas = Employees.Where(employee => employee.IsDeleted == false && employeeIds.Contains(employee.Id)).Select(employee => new
                                                                                                                                                          {
                                                                                                                                                              Employee = employee,
                                                                                                                                                              Properties = employee.InternalLeaseAgreements.Where(leaseAgreement => leaseAgreement.IsDeleted == false && leaseAgreement.InternalLeaseContracts.Any(contract => contract.IsDeleted == false && contract.SignatureDate >= beginDate && contract.SignatureDate < endDate) && leaseAgreement.Property.IsDeleted == false && leaseAgreement.Property.ActiveLeaseAgreementId == leaseAgreement.Id && leaseAgreement.Property.PropertyStateId == 4).Select(leaseAgreement => leaseAgreement.Property)
                                                                                                                                                          }).ToList();
            return employeeLeaseAreas.ToDictionary(employeeLeaseArea => employeeLeaseArea.Employee, employeeLeaseArea => Tuple.Create(employeeLeaseArea.Properties.Sum(property => property.LeaseArea), employeeLeaseArea.Properties.Count()));
        }

        /// <summary>
        /// </summary>
        /// <param name = "employees"></param>
        /// <param name = "beginDate"></param>
        /// <param name = "endDate"></param>
        /// <returns></returns>
        public IDictionary<Employee, Tuple<decimal, decimal, int, int>> GetEmployeesSaleAreaAndLeaseArea(IList<Employee> employees, DateTime beginDate, DateTime endDate)
        {
            var employeeIds = employees.Select(employee => employee.Id).Distinct().ToList();
            var employeeSaleAreasAndLeaseAreas = Employees.Where(employee => employee.IsDeleted == false && employeeIds.Contains(employee.Id)).Select(employee => new
                                                                                                                                                                      {
                                                                                                                                                                          Employee = employee,
                                                                                                                                                                          Rooms = employee.InternalAgreements.Where(agreement => agreement.IsDeleted == false && agreement.InternalContracts.Any(contract => contract.IsDeleted == false && contract.SignatureDate >= beginDate && contract.SignatureDate < endDate) && agreement.Room.IsDeleted == false && agreement.Room.ActiveAgreementId == agreement.Id && (agreement.Room.RoomStateId == 5 || agreement.Room.RoomStateId == 6)).Select(agreement => agreement.Room),
                                                                                                                                                                          Properties = employee.InternalLeaseAgreements.Where(leaseAgreement => leaseAgreement.IsDeleted == false && leaseAgreement.InternalLeaseContracts.Any(contract => contract.IsDeleted == false && contract.SignatureDate >= beginDate && contract.SignatureDate < endDate) && leaseAgreement.Property.IsDeleted == false && leaseAgreement.Property.ActiveLeaseAgreementId == leaseAgreement.Id && leaseAgreement.Property.PropertyStateId == 4).Select(leaseAgreement => leaseAgreement.Property)
                                                                                                                                                                      }).ToList();
            return employeeSaleAreasAndLeaseAreas.ToDictionary(employeeSaleAreaAndLeaseArea => employeeSaleAreaAndLeaseArea.Employee, employeeSaleAreaAndLeaseArea => Tuple.Create(employeeSaleAreaAndLeaseArea.Rooms.Sum(room => room.SaleArea), employeeSaleAreaAndLeaseArea.Properties.Sum(property => property.LeaseArea), employeeSaleAreaAndLeaseArea.Rooms.Count(), employeeSaleAreaAndLeaseArea.Properties.Count()));
        }

        #endregion
    }
}